package domain.stack;

import java.util.concurrent.atomic.AtomicReference;

public class IlConcurrentStack_v2 <E> extends AbstractConcurrentStack<E>{
	
	private int m_smallNumber; 
	private AtomicReference<IlNode<E>> top = new AtomicReference<IlNode<E>>();

	
	public IlConcurrentStack_v2(int aSmallNumber) {
		m_smallNumber = aSmallNumber;
	}


	@SuppressWarnings("unchecked")
	public void push(E item) {
		IlNode<E> newHead = new IlNode<E>(item);
		IlNode<E> oldHead;
		while (true){
			oldHead = top.get();
			newHead.next = oldHead;
			if ((oldHead != null) && (oldHead.nodesStatus.get() == Status.UNSTBL)){ // need to help previous pop
				top.compareAndSet(oldHead, oldHead.next);
			} else if (top.compareAndSet(oldHead, newHead)){ 
				return;
			} else { // try to push roughly
				IlNode<E> u = top.get();
				int k = 0;
				// find the location to push in 
				while ((u != null && u.next != null) && (u.next != oldHead) && (k<m_smallNumber)) {
					u = u.next;
					++k;
				}
				if((u != null /*&& u.next == oldHead -- the only change for v2 --*/) && (u.nodesStatus.get() == Status.STBL)){
					// push roughly
					if(u.compareAndSet(oldHead, newHead)) {
						return;
					}
				}
			}
		}
	}

	public E pop() {
		IlNode<E> oldHead;
		IlNode<E> newHead;
		while (true){
			oldHead = top.get();
			if (oldHead == null)
				return null;
			newHead = oldHead.next;
			if (oldHead.nodesStatus.compareAndSet(Status.STBL, Status.UNSTBL)){
				top.compareAndSet(oldHead, newHead);
				return oldHead.item;
			}
			else { // help to previous pop 
				top.compareAndSet(oldHead, newHead);
			}
		}
	}
}
